[pull] main from rmyndharis:main - #115
Merged
Merged
Conversation
Two defects in the outbound delivery record, both reachable on the default deployment. The reconciler decided a replay had worked by whether `redeliver()` threw, and it cannot: every failing path inside it dead-letters, hooks and logs in place, so the call resolves either way. A replay to a receiver that was still down was therefore retired as 'dispatched' with its payload nulled on the very first sweep, and `findStale` never sees it again. The documented WEBHOOK_RECONCILE_MAX_ATTEMPTS budget was unreachable, the catch block was dead code whose comment claimed the opposite, and stats counted the event as replayed. Delivery now returns an outcome, the way the inbound twin already does, and a failed replay stays pending until the budget is spent. The import never cleared `webhook_outbox_events`. It carries no foreign key to sessions, so the sessions DELETE did not reach it, and UNIQUE(webhookId, idempotencyKey) then collided on every overlapping row until the all-or-nothing gate rolled the entire import back. Restoring a backup onto the instance that produced it is the rollback flow, so this broke recovery rather than a corner of it. The reconciler spec mocked a rejected promise, a shape the real collaborator cannot produce, so it green-lit a budget it never exercised; it now mocks the outcome. The round-trip spec cleared each table before importing, which is why the collision never surfaced; the new case deliberately does not.
Three defects in the caller-named read receipt, all reachable from the public route. `@IsOptional` skips every validator when the value is null as well as undefined, so `"messageIds": null` passed validation, reached the Baileys adapter and was dereferenced there: a 500 on a malformed body that should have been a 400. The DTO now validates a present-but-null value, and the adapter treats null as absent so an internal caller cannot reproduce it either. The published schema gains `minItems`, which it needed anyway: it advertised an empty array the server refuses. A stored key carries its own remoteJid, and it was used unchecked. An id belonging to a different chat in the same session therefore sent the receipt to that chat while the route answered success for the one named in the path, leaving the caller's own chat unread. Stored keys are now used only when they resolve to the addressed chat, folded through toEngineJid so the @c.us and @s.whatsapp.net spellings still match; anything else falls back to the synthesised key for the addressed chat, which is what every id ran on before the store was consulted. The Go client tagged `messageIds` `omitempty` on a plain slice, so an empty list was dropped from the body and the server read it as "acknowledge the newest message", the exact collapse the empty-array refusal exists to prevent. The field is a pointer, so absent and empty are distinct on the wire. The type has never shipped, so nothing external moves. The breaking-change note also understated its own scope: markRead is source-breaking on Go and Java alongside subscribePresence, and typed Python callers fail mypy on both. Verified against the published 0.4.0 signatures rather than assumed; JavaScript is structural and unaffected.
Both scripts resolve every other data path through openwa_resolve and then hardcoded the plugin state as $OPENWA_DATA_DIR/plugins. With the knob set, the archive carried neither the registry nor any plugin's persisted ctx.storage, and a restore put nothing back. Silent in both directions: an absent source directory simply produces no plugin-state entry, so the backup still exits 0 and only a restore reveals what is missing. The local variable shares its name with the knob, which is what made the line read as if it already honoured it. The resolved root now has its own name, because the knob points at the ROOT and the state sits at <root>/plugins. The knob's note told operators to move registry.json. That leaves every plugin enabled with its state gone, since each plugin's ctx.storage sits beside the registry as <plugin id>/key-*.json; it now names the whole tree. Smoke case (g) covers both legs. Reverting either script alone fails it with that script's own message.
…d-restore fix(webhook): report the delivery outcome and clear the outbox on import
…scope fix(session): refuse a null id list and keep read receipts in their chat
fix(scripts): resolve PLUGIN_STATE_DIR in backup and restore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )